package com.settlement.system.controller;

import com.alibaba.excel.ExcelWriter;
import com.settlement.system.common.enums.CostAllocationWeightEnum;
import com.settlement.system.common.enums.ExcelFileType;
import com.settlement.system.common.exception.ServiceException;
import com.settlement.system.common.util.common.DictionaryUtil;
import com.settlement.system.common.util.common.FasUtil;
import com.settlement.system.csv.CsvDatas;
import com.settlement.system.csv.CsvExportBuilder;
import com.settlement.system.csv.CsvExportUtil;
import com.settlement.system.model.entity.common.*;
import com.settlement.system.reply.ObjectDataResponse;
import com.settlement.system.service.*;
import com.settlement.system.service.csv.TblCostWeightRecordCsvDatas;
import io.swagger.annotations.ApiOperation;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.*;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.RecursiveAction;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

/**
 * @author
 */
@Slf4j
@RestController
@RequestMapping("/tblCostAllocationWeight")
public class TblCostAllocationWeightController extends BaseController<TblCostAllocationWeight> {

    @Value("${system.export-root.path}")
    private String exportRootPath;

    @Resource
    private ITblCostWeightSummaryService tblCostWeightSummaryService;

    @Resource
    private ITblCostWeightRecordService tblCostWeightRecordService;

    @Resource
    private ITblCostWeightOrderService tblCostWeightOrderService;

    @Resource
    private IWpSummaryService iWpSummaryService;


    @Resource
    private ITblRrChannelService tblRrChannelService;


    @Resource
    private ITblWpVendorConfigService iTblWpVendorConfigService;

    @Autowired


    @Resource
    private DictionaryUtil dictionaryUtil;

    @Override
    public IBaseService init() {
        return iWpSummaryService;
    }

    @Override
    protected void setFootModel(Map<String, Object> result, Map<String, Object> model) throws ServiceException {
        WpSummary foot = iWpSummaryService.selectFoot(model);
        result.put("foot", foot);
        super.setFootModel(result, model);
    }

    @GetMapping("export")
    public void export(HttpServletRequest request, HttpServletResponse response) throws Exception {

        try {
            Map<String, Object> params = buildParam(request);
            setParamsModel(params);
            File file = new File(exportRootPath + "费用分配权数" + System.currentTimeMillis() + "/");
            if (!file.exists()) {
                file.mkdirs();
            }

            Set<String> orderTypeSet = getOrderTypes(params.get("orderTypes"));

            List<WpExport> wpExports = new ArrayList<WpExport>();
            if (orderTypeSet.contains(CostAllocationWeightEnum.PAGE_TAB.ALL.name()) || orderTypeSet.contains(CostAllocationWeightEnum.PAGE_TAB.FTHHZ.name())) {
                wpExports.add(submit(tblCostWeightSummaryService, file.getAbsolutePath(), "发退货汇总.xlsx", params, TblCostWeightSummary.class));
            }

            if (orderTypeSet.contains(CostAllocationWeightEnum.PAGE_TAB.ALL.name()) || orderTypeSet.contains(CostAllocationWeightEnum.PAGE_TAB.CZJL.name())) {
                wpExports.add(submit(tblCostWeightRecordService, file.getAbsolutePath(), "操作记录.xlsx", params, TblCostWeightRecord.class));
            }

            if (orderTypeSet.contains(CostAllocationWeightEnum.PAGE_TAB.ALL.name()) || orderTypeSet.contains(CostAllocationWeightEnum.PAGE_TAB.DDLB.name())) {
                wpExports.add(submit(tblCostWeightOrderService, file.getAbsolutePath(), "订单列表.xlsx", params, TblCostWeightOrder.class));
            }

            for (WpExport info : wpExports) {
                info.get();
            }

            exportZip(request, response, file);
        } catch (Exception ex) {
            log.error("费用分配权数导出异常", ex);
            throw ex;
        }
    }

    private Set<String> getOrderTypes(Object orderTypes) {
        Set<String> orderTypeSet = new HashSet<>();

        if (orderTypes != null) {
            String[] strs = orderTypes.toString().split(",");
            for (int index = 0; index < strs.length; index++) {
                orderTypeSet.add(strs[index]);
            }
        }
        if (orderTypeSet.size() == 0) {
            orderTypeSet.add("ALL");
        }
        return orderTypeSet;
    }

    public void exportZip(HttpServletRequest request, HttpServletResponse response, File pathFile) throws ServiceException {
        ZipOutputStream out = null;
        try {
            String zipfileName = "wpAccount.zip";
            final String userAgent = "User-Agent";
            final String firefox = "firefox";
            out = new ZipOutputStream(response.getOutputStream());
            if (request.getHeader(userAgent).toLowerCase().indexOf(firefox) > 0) {
                zipfileName = new String(zipfileName.getBytes("GB2312"), "ISO-8859-1");
            } else {
                zipfileName = java.net.URLEncoder.encode(zipfileName, "UTF-8");
                zipfileName = new String(zipfileName.getBytes("UTF-8"), "GBK");
            }

            out = new ZipOutputStream(response.getOutputStream());
            response.reset();
            response.setCharacterEncoding("UTF-8");
            response.setContentType("application/x-msdownload");
            response.setHeader("Content-Disposition", "attachment;filename=" + zipfileName);

            byte[] buf = new byte[4096];

            for (File file : pathFile.listFiles()) {
                FileInputStream in = null;

                try {
                    in = new FileInputStream(file);
                    String fileName = file.getName();
                    out.putNextEntry(new ZipEntry(fileName));

                    int len;
                    while ((len = in.read(buf)) > 0) {
                        out.write(buf, 0, len);
                    }
                    out.closeEntry();
                } catch (Exception e) {
                    log.info("文件压缩流导入异常", e);
                    throw new ServiceException("文件压缩流导入异常", e);
                } finally {
                    if (in != null) {
                        in.close();
                    }
                }
            }
            deleteDir(pathFile);

        } catch (Exception e) {
            throw new ServiceException("导出压缩包文件异常", e);
        } finally {
            try {
                if (out != null) {
                    out.close();
                }
            } catch (IOException e) {
                log.info("关闭Zip文件输入流异常");
            }
        }
    }

    /**
     * 删除文件夹
     *
     * @param dir
     */
    private static void deleteDir(File dir) {

        if (dir == null) {
            throw new NullPointerException("the dir is null.");
        }

        if (dir.isDirectory()) {
            File[] files = dir.listFiles();
            for (File file : files) {

                if (file.isDirectory()) {
                    deleteDir(file); // 递归删除
                } else {
                    file.delete();
                }
            }
            dir.delete();
        } else {
            dir.delete();
        }
    }


    private WpExport submit(IBaseService baseService, String path, String fileName, Map<String, Object> params, Class aclass) {
        ForkJoinPool pool = ForkJoinPool.commonPool();
        WpExport wpExport = new WpExport(baseService, path, fileName, params, aclass);
        pool.submit(wpExport);
        return wpExport;
    }

    /**
     * 唯品导出的任务
     */
    public class WpExport extends RecursiveAction {

        public IBaseService baseService;
        public String fileName;
        public String path;
        public Class aClass;
        public Map<String, Object> params;
        String fileType;
        ExcelWriter excelWriter;
        private Integer singleFileRowsNum = 500000;

        //xlsx的fileName带后缀，csv的不带后缀
        public WpExport(IBaseService baseService, String path, String fileName, Map<String, Object> params, Class aClass) {
            this.baseService = baseService;
            this.path = path;
            this.fileName = fileName;
            this.params = (Map<String, Object>) ((HashMap) params).clone();
            this.aClass = aClass;
            checkFileName();
        }

        void checkFileName() {
            this.fileType = (String) this.params.get("fileType");
            if (fileType == null) {
                fileType = ExcelFileType.XLSX.toString();
            }

            if (fileName.toLowerCase().endsWith(ExcelFileType.CSV.name().toLowerCase()) || fileName.toLowerCase().endsWith(ExcelFileType.XLSX.name().toLowerCase())) {
                int pos = fileName.lastIndexOf(".");
                fileName = fileName.substring(0, pos);
            }
        }

        @Override
        protected void compute() {
            try {
                if (baseService.selectCount(params) <= 0) {
                    return;
                }

                CsvExportUtil.createCsv()
                        .headClass(aClass)
                        .fileName(fileName)
                        .fileType(ExcelFileType.getByName(this.fileType))
                        .model(CsvExportBuilder.MULTI_NOT_ZIP_MODEL)
                        .parentPath(path + File.separator)
                        .csvDatas(getCsvDatas(params, baseService))
                        .generateFile();

            } catch (Exception ex) {
                log.error(ex.getMessage(), ex);

                completeExceptionally(ex);
            }
        }

        private String excelFileName(int resultCount) {
            return StringUtils.replace(fileName, ".", "_" + resultCount / singleFileRowsNum + ".");
        }
    }

    @Override
    protected void setParamsModel(Map<String, Object> model) {
        String nameShort = dictionaryUtil.getNameShortShowChildBrandName();
        if (StringUtils.isNotEmpty(nameShort)) {
            model.put("nameShort", nameShort);
        }
        String channelNo = (String) model.get("channelNo");
        if (StringUtils.isNotEmpty(channelNo)) {
            List<String> channelNoList = Arrays.asList(channelNo.split(","));
            model.put("channelNoList", channelNoList);
        }
        FasUtil.formatInQueryCondition(model, "shopNo", "billNumberType", "settleAccountPeriod",
                "brandNo", "processStatus", "categoryName", "billNumber", "calendar",
                "globalId", "so", "poNo", "barcode", "deliveryType", "channelNo", "accountingPeriod", "nameShort", "companyNo");
        super.setParamsModel(model);
    }

    @ApiOperation("刷新进度状态")
    @RequestMapping(value = "updateProcessStatus", method = {RequestMethod.POST})
    @ResponseBody
    protected ObjectDataResponse updateProcessStatus(@RequestBody WpSummary model, HttpServletRequest request) {
        try {
            if (StringUtils.isEmpty(model.getBillNumber())) {
                return new ObjectDataResponse(500, "账单编码不能为空");
            }

            iWpSummaryService.updateProcessStatus(model);
            return new ObjectDataResponse(200, "更新成功");
        } catch (Exception ex) {
            log.info("更新数据异常", ex);
            return new ObjectDataResponse(500, "更新失败，请联系管理员！");
        }
    }

    @ApiOperation("财务确认")
    @RequestMapping(value = "sign", method = {RequestMethod.POST})
    @ResponseBody
    protected ObjectDataResponse sign(@RequestBody WpSummary model, HttpServletRequest request) {
        try {

            if (StringUtils.isEmpty(model.getBillNumber())) {
                return new ObjectDataResponse(500, "账单编码不能为空");
            }

            String message = iWpSummaryService.sign(model);
            if (!StringUtils.isEmpty(message)) {
                return new ObjectDataResponse(500, message);
            }
            return new ObjectDataResponse(200, "更新成功");
        } catch (Exception ex) {
            log.info("更新数据异常", ex);
            return new ObjectDataResponse(500, "更新失败，请联系管理员！");
        }
    }


    @ApiOperation("下载账单")
    @RequestMapping(value = "download", method = {RequestMethod.POST})
    @ResponseBody
    protected ObjectDataResponse download(@RequestBody WpSummary model, HttpServletRequest request) {
        try {

            if (StringUtils.isEmpty(model.getShopNo())) {
                return new ObjectDataResponse(500, "店铺编码不能为空");
            }

            String[] shopNos = model.getShopNo().split(",");
            List<String> vendorCodes = iTblWpVendorConfigService.getVendorCodes(new ArrayList<>(Arrays.asList(shopNos)));
            iWpSummaryService.download(vendorCodes);
            return new ObjectDataResponse(200, "执行成功");
        } catch (Exception ex) {
            log.info("下载账单异常", ex);
            return new ObjectDataResponse(500, "下载账单失败，请联系管理员！");
        }
    }

    protected CsvDatas getCsvDatas(Map<String, Object> params, IBaseService baseService) throws ServiceException {
        TblCostWeightRecordCsvDatas csvDatas = new TblCostWeightRecordCsvDatas(
                baseService,
                params,
                tblRrChannelService);
        return csvDatas;
    }
}
